<?php

declare(strict_types=1);

namespace app\controller\system\product;

use app\BaseController;
use app\model\OrgMember;
use app\model\Prod as ProdModel;
use app\service\factory\ResponseFactory;
use app\service\product\ProductImportJobService;
use app\service\product\ProductImportStorageService;
use app\service\product\ProdService;
use app\validate\product\ProdBulkValidate;
use app\validate\product\ProdValidate;
use InvalidArgumentException;
use think\facade\Log;
use think\Response;
use Throwable;

class Prod extends BaseController
{
    public function index(ProdService $prodService): Response
    {
        try {
            $page = max(1, (int) $this->request->param('page', 1));
            $pageSize = (int) $this->request->param('page_size', 20);
            $pageSize = $pageSize > 0 ? min($pageSize, 100) : 20;

            $filters = $this->request->only([
                'keyword',
                'status',
                'audit_status',
                'category_id',
                'brand_id',
                'seller_org_id',
            ], 'get');

            $paginator = $prodService->paginate($filters, $page, $pageSize);
            $list = $prodService->formatCollection($paginator->items());

            return json(ResponseFactory::paginated(
                $list,
                (int) $paginator->total(),
                $page,
                $pageSize
            ));
        } catch (Throwable $e) {
            return json(ResponseFactory::error($e->getMessage(), $e->getCode() ?: 500));
        }
    }

    public function read(int $id, ProdService $prodService): Response
    {
        try {
            $prod = $prodService->findById($id);
            if (!$prod) {
                return json(ResponseFactory::error('商品不存在', 404));
            }

            return json(ResponseFactory::success($prodService->format($prod)));
        } catch (Throwable $e) {
            return json(ResponseFactory::error($e->getMessage(), $e->getCode() ?: 500));
        }
    }

    public function save(ProdService $prodService): Response
    {
        try {
            $payload = $this->request->only([
                'seller_org_id',
                'seller_user_id',
                'region_id',
                'category_id',
                'brand_id',
                'title',
                'subtitle',
                'model',
                'sku_code',
                'cover_image',
                'gallery',
                'videos',
                'default_price',
                'default_stock',
                'unit',
                'min_order_qty',
                'step_qty',
                'weight_value',
                'weight_unit',
                'size_length',
                'size_width',
                'size_height',
                'origin_country',
                'manufactured_at',
                'summary',
                'description',
                'attachments',
                'attributes',
                'status',
                'audit_status',
                'publish_time',
                'remark',
            ], 'post');

            $payload = $this->fillSellerOrgId($payload);
            $payload = $prodService->normalizeProductInput($payload);

            $this->validate($payload, ProdValidate::class . '.create');

            $prod = $prodService->create($payload);

            return json(ResponseFactory::success($prodService->format($prod), '商品已创建'));
        } catch (InvalidArgumentException $e) {
            return json(ResponseFactory::error($e->getMessage(), 422));
        } catch (Throwable $e) {
            Log::error('商品创建失败', [
                'message' => $e->getMessage(),
                'code' => $e->getCode(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString(),
            ]);
            return json(ResponseFactory::error($e->getMessage(), $e->getCode() ?: 500));
        }
    }

    public function update(int $id, ProdService $prodService): Response
    {
        try {
            $prod = ProdModel::find($id);
            if (!$prod) {
                return json(ResponseFactory::error('商品不存在', 404));
            }

            $payload = $this->request->only([
                'seller_org_id',
                'seller_user_id',
                'region_id',
                'category_id',
                'brand_id',
                'title',
                'subtitle',
                'model',
                'sku_code',
                'cover_image',
                'gallery',
                'videos',
                'default_price',
                'default_stock',
                'unit',
                'min_order_qty',
                'step_qty',
                'weight_value',
                'weight_unit',
                'size_length',
                'size_width',
                'size_height',
                'origin_country',
                'manufactured_at',
                'summary',
                'description',
                'attachments',
                'attributes',
                'status',
                'audit_status',
                'publish_time',
                'remark',
            ], 'put');
            $payload['id'] = $id;
            $payload = $this->fillSellerOrgId($payload);
            $payload = $prodService->normalizeProductInput($payload);

            $this->validate($payload, ProdValidate::class . '.update');

            $updated = $prodService->update($prod, $payload);

            return json(ResponseFactory::success($prodService->format($updated), '商品已更新'));
        } catch (InvalidArgumentException $e) {
            return json(ResponseFactory::error($e->getMessage(), 422));
        } catch (Throwable $e) {
            return json(ResponseFactory::error($e->getMessage(), $e->getCode() ?: 500));
        }
    }

    public function delete(int $id, ProdService $prodService): Response
    {
        try {
            $prod = ProdModel::find($id);
            if (!$prod) {
                return json(ResponseFactory::error('商品不存在', 404));
            }

            if (!$prodService->delete($prod)) {
                return json(ResponseFactory::error('删除失败', 500));
            }

            return json(ResponseFactory::success(true, '商品已删除'));
        } catch (Throwable $e) {
            return json(ResponseFactory::error($e->getMessage(), $e->getCode() ?: 500));
        }
    }

    public function bulkUpload(
        ProdService $prodService,
        ProductImportJobService $jobService,
        ProductImportStorageService $storageService
    ): Response {
        try {
            $file = $this->request->file('file');
            if (!$file) {
                throw new InvalidArgumentException('请上传导入文件');
            }

            $mappingInput = $this->request->post('mapping', '');
            if (is_array($mappingInput)) {
                $mapping = $mappingInput;
            } else {
                $mapping = json_decode((string) $mappingInput, true);
            }
            if (!is_array($mapping) || $mapping === []) {
                throw new InvalidArgumentException('字段映射不能为空');
            }

            $basePayload = $this->request->post();
            unset($basePayload['mapping'], $basePayload['options'], $basePayload['total_rows']);
            $basePayload = $this->fillSellerOrgId($basePayload);

            $optionsInput = $this->request->post('options', []);
            if (is_array($optionsInput)) {
                $options = $optionsInput;
            } else {
                $decodedOptions = json_decode((string) $optionsInput, true);
                $options = is_array($decodedOptions) ? $decodedOptions : [];
            }

            $totalRows = (int) $this->request->post('total_rows', 0);

            $stored = $storageService->storeUpload($file);

            $allowDuplicate = $this->toBoolean($this->request->post('allow_duplicate', false));

            $job = $jobService->createJob(
                $basePayload,
                $stored['path'],
                $stored['hash'],
                $mapping,
                array_merge($options, [
                    'original_filename' => $stored['original_name'] ?? $file->getOriginalName(),
                ]),
                (int) config('product.bulk_chunk_size', 20),
                $totalRows,
                $allowDuplicate
            );

            return json(ResponseFactory::success([
                'job_id' => (int) $job->id,
                'status' => $job->status,
                'total_rows' => (int) $job->total_rows,
                'chunk_size' => (int) $job->chunk_size,
                'created_at' => $job->create_time,
                'duplicate' => (bool) $job->getAttr('duplicate'),
            ], $job->getAttr('duplicate') ? '存在相同的导入任务，已复用' : '导入任务已创建，系统将后台处理'));
        } catch (InvalidArgumentException $e) {
            return json(ResponseFactory::error($e->getMessage(), 422));
        } catch (Throwable $e) {
            return json(ResponseFactory::error($e->getMessage(), $e->getCode() ?: 500));
        }
    }

    private function fillSellerOrgId(array $payload): array
    {
        $current = isset($payload['seller_org_id']) ? (int) $payload['seller_org_id'] : 0;
        if ($current > 0) {
            if (empty($payload['seller_user_id']) && $this->request->user_id) {
                $payload['seller_user_id'] = (int) $this->request->user_id;
            }
            return $payload;
        }

        $orgId = $this->resolveSellerOrgId();
        if ($orgId !== null) {
            $payload['seller_org_id'] = $orgId;
            if (empty($payload['seller_user_id']) && $this->request->user_id) {
                $payload['seller_user_id'] = (int) $this->request->user_id;
            }
        }

        return $payload;
    }

    private function resolveSellerOrgId(): ?int
    {
        $payload = (array) ($this->request->payload ?? []);
        $groups = $payload['groups'] ?? [];
        if (is_array($groups)) {
            foreach ($groups as $group) {
                if (is_string($group) && strncmp($group, 'seller_', 7) === 0) {
                    $orgId = (int) substr($group, 7);
                    if ($orgId > 0) {
                        return $orgId;
                    }
                }
            }
        }

        $userId = (int) ($this->request->user_id ?? 0);
        if ($userId <= 0) {
            return null;
        }

        $member = OrgMember::where('user_id', $userId)
            ->where('status', 1)
            ->find();

        return $member ? (int) $member->org_id : null;
    }

    private function toBoolean(mixed $value): bool
    {
        if (is_bool($value)) {
            return $value;
        }

        if (is_numeric($value)) {
            return (bool) $value;
        }

        if (is_string($value)) {
            return in_array(strtolower($value), ['1', 'true', 'yes', 'on'], true);
        }

        return false;
    }
}
